import os
import re
from typing import Pattern
import matplotlib.pyplot as plt
import pandas as pd


def compile(source_path: str, output_path: str):
    os.system("gcc -Og -pg {} -o {}".format(source_path, output_path))


def run_stat(program: str, repeat: int, event: list, output_file: str) -> dict:
    event_list_str = ",".join(event)
    os.system("perf stat -B --repeat {} -e {} -o {} ./{}".format(repeat,
                                                                 event_list_str,
                                                                 output_file,
                                                                 program))
    result_dict = analyze_stat_result(repeat, event, output_file)
    return result_dict


def analyze_stat_result(repeat: int, event: list, output_file: str) -> dict:
    result_dict = {}
    with open(output_file, "r") as f:
        result_lines = f.readlines()
    result_dict["time"] = result_lines[0][13:-1]
    result_dict["test file"] = re.compile(
        "'(.*)'").findall(result_lines[3])[0][2:]
    if repeat == 1:
        result_dict["repeat"] = 1
    else:
        result_dict["repeat"] = int(re.compile(
            r"[(](.+) runs[)]").findall(result_lines[3])[0])
    for i, event_item in enumerate(event):
        result_dict[event_item] = int(
            result_lines[5 + i][0:20].strip().replace(",", ""))
    return result_dict


# 实验：event数量对采样结果的影响，event数量从1变化到7，观测cycles结果的变化情况，每次重复运行50次，画出箱线图
def test_event_num_cycle():
    # 初始event列表，第i次实验包含前i个event
    event_list = ["cycles", "instructions", "cache-references",
                  "ref-cycles", "bus-cycles", "branches", "branch-misses"]
    result_dict = {}
    for i in range(1, 8):
        cycles = []
        for j in range(0, 100):
            result = run_stat(program="workspace/perf_stat_example",
                              repeat=1,
                              event=event_list[0:i],
                              output_file="workspace/perf_stat_result.log")
            cycles.append(result["cycles"])
        result_dict[str(i)] = cycles.copy()
        cycles.clear()
    result_pd = pd.DataFrame(result_dict)
    plt.boxplot([result_pd[str(x)] for x in range(1, 8)], vert=False, showmeans=True)
    plt.show()
    print(result_pd.std().tolist())
    plt.plot([x for x in range(1, 8)], result_pd.std().tolist())
    plt.show()


if __name__ == "__main__":
    # 编译代码
    compile(source_path="workspace/perf_stat_example.c",
            output_path="workspace/perf_stat_example")

    event_list = ["cpu-cycles", "ref-cycles"]
    result = run_stat(program="workspace/perf_stat_example",
                      repeat=50,
                      event=event_list,
                      output_file="workspace/perf_stat_result.log")
    print(result)
    # test_event_num_cycle()
